﻿namespace Manhua2.Common
{
    using Manhua2.DataModel;
    using Manhua2.Helper;
    using Manhua2.Provider;
    using Manhua2.SQLiteTable;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Threading.Tasks;

    public sealed class ModelContext :IDisposable
    {
        public ModelContext()
        { 
        }

        public async Task<ObservableCollection<ComicItem>> QueryLatestComicsAsync(IComicProvider provider)
        {
            using (DbContext context = new DbContext())
            {
                var query = await context.QueryAsync<SQLiteChapter>(
                    string.Format("SELECT * FROM chapters WHERE comic_id in " +
                        "(SELECT id FROM comics WHERE provider = ?) ORDER BY updated DESC LIMIT {0}", provider.TopCount),
                    provider.ToString());

                ObservableCollection<ComicItem> results = new ObservableCollection<ComicItem>();

                foreach (var item in query)
                {
                    var comic = await context.GetAsync<SQLiteComic>(item.ComicId);
                    var bind = new ComicItem(comic, item)
                    {
                        ChapterTitle = item.Title,
                        ComicTitle = comic.Title,
                        Timestamp = item.Updated.ToString(),
                    };

                    if (await MethodHelper.FileIsExists("cover\\" + comic.Id))
                    {
                        bind.Cover = "ms-appdata:///local/cover/" + comic.Id;
                    }

                    results.Add(bind);
                }

                return results;
            }
        }

        public async Task<Chapter> GetChapterAsync(int chapterId)
        {
            using (DbContext context = new DbContext())
            {
                // 查询数据库, 获取chapter
                var chapter = await this.GetChapterAsync(context, chapterId);

                // 查询数据库，获取comic
                var comic = await this.GetComicAsync(context, chapter.ComicId);

                // 获取历史记录 history
                var his = await this.GetHistoryAsync(context, chapter.Id);

                // 读取URL
                if (string.IsNullOrEmpty(chapter.Url))
                {
                    IComicProvider provider = ComicProviderFactory.Create(comic.Provider);
                    await provider.SaveChaptersAsync(comic.Id);
                    chapter = await this.GetChapterAsync(context, chapterId);
                }

                // 获取所有页 pages
                // 如果pages为空, 启动获取章节所有页面地址的方法
                if (chapter.TotalPage == 0)
                {
                    IComicProvider provider = ComicProviderFactory.Create(comic.Provider);
                    await provider.SavePagesAsync(chapterId);
                    chapter = await this.GetChapterAsync(context, chapterId);
                }

                var pages = await this.QueryPagesAsync(context, chapterId);

                Chapter result = new Chapter()
                {
                    ChapterTitle = chapter.Title,
                    ComicTitle = comic.Title,
                    Pages = new List<ComicPage>(),
                    TotalPage = chapter.TotalPage,

                    ComicId = comic.Id,
                    ChapterId = chapter.Id
                };

                foreach (var page in pages)
                {
                    var url = new ComicPage()
                    {
                        Page = page.Page,
                        ComicId = comic.Id,
                        ChapterId = chapter.Id,
                        SourceUrl = page.Url,
                    };

                    if (await MethodHelper.FileIsExists(string.Format("comic\\{0}\\{1}\\{2}",
                                                                comic.Id, chapter.Id, page.Page)))
                    {
                        url.Url = string.Format("ms-appdata:///local/comic/{0}/{1}/{2}",
                                                comic.Id, chapter.Id, page.Page);
                    }

                    result.Pages.Add(url);
                }

                return result;
            }
        }

        public async Task<ComicItem> GetComicAsync(int comicId)
        {
            using (DbContext context = new DbContext())
            {
                var query = await context.GetAsync<SQLiteComic>(comicId);
                var comic = new ComicItem(query, null)
                {
                    ComicTitle = query.Title,
                    Author = query.Author,
                };

                if (await MethodHelper.FileIsExists("cover\\" + query.Id))
                {
                    comic.Cover = "ms-appdata:///local/cover/" + query.Id;
                }
                else
                {
                    comic.Cover = query.CoverUrl;
                }

                return comic;
            }
        }

        public async Task<int> GetHistoryPageAsync(int chapterId)
        {
            using (DbContext context = new DbContext())
            {
                var his = await this.GetHistoryAsync(context, chapterId);
                if (his == null) return 0;
                return his.Page;
            }
        }

        public async Task<ObservableCollection<ComicItem>> QueryHistoriesAsync(int top)
        {
            using (DbContext context = new DbContext())
            {
                // 检查TOP值
                if (top < 0) throw new ArgumentNullException("top");
                ObservableCollection<ComicItem> results = new ObservableCollection<ComicItem>();

                // 首先查询最近观看的所有漫画， 按照时间倒叙， 取前top个
                var query = await context.QueryAsync<SQLiteComic>(
                    "SELECT chapters.comic_id id FROM histories " +
                    " INNER JOIN chapters ON histories.chapter_id = chapters.id" +
                    " GROUP BY chapters.comic_id" +
                    " ORDER BY MAX(histories.last_view) DESC" +
                    " LIMIT " + top);

                // 遍历生成结果
                foreach (var item in query)
                {
                    // 由于首次查询只获取了ID， 在这里获取该漫画具体信息
                    var comic = await context.GetAsync<SQLiteComic>(item.Id);

                    // 获取该漫画最近一次观看详细
                    var his = (await context.QueryAsync<SQLiteHistory>(
                        "SELECT histories.* FROM histories " +
                        " INNER JOIN chapters ON histories.chapter_id = chapters.id " +
                        " WHERE chapters.comic_id = ? " +
                        " ORDER BY histories.last_view desc " +
                        " LIMIT 1", item.Id)).FirstOrDefault();

                    if (his == null) continue;

                    // 获取最近观看的章节
                    var chapter = await context.GetAsync<SQLiteChapter>(his.ChapterId);

                    var bind = new ComicItem(comic, chapter)
                    {
                        ComicTitle = comic.Title,
                        ChapterTitle = chapter.Title,
                        Timestamp = his.LastView.ToString(),
                    };

                    if (await MethodHelper.FileIsExists("cover\\" + comic.Id))
                    {
                        bind.Cover = "ms-appdata:///local/cover/" + comic.Id;
                    }
                    //else
                    //{
                    //    bind.Cover = comic.CoverUrl;
                    //}

                    // 生成添加到结果
                    results.Add(bind);
                }

                return results;
            }
        }

        public async Task<List<int>> QueryChaptersIdAsync(int comicId)
        {
            using (DbContext context = new DbContext())
            {
                var query = await context.QueryAsync<SQLiteChapter>("SELECT id FROM chapters WHERE comic_id = ? ORDER BY updated, id", comicId);
                return (from p in query
                        select p.Id).ToList();
            }
        }

        public async Task<ObservableCollection<Chapter>> QueryChaptersAsync(int comicId)
        {
            using (DbContext context = new DbContext())
            {
                var query = await context.QueryAsync<SQLiteChapter>("SELECT id, title, total_page FROM chapters WHERE comic_id = ? ORDER BY updated, id", comicId);
                return new ObservableCollection<Chapter>((from p in query
                                                          select new Chapter()
                                                          {
                                                              ChapterId = p.Id,
                                                              ChapterTitle = p.Title,
                                                              TotalPage = p.TotalPage
                                                          }));
            }
        }

        public async Task<ObservableCollection<ComicItem>> QueryComicsAsync(string text)
        {
            ObservableCollection<ComicItem> results = new ObservableCollection<ComicItem>();

            using (DbContext context = new DbContext())
            {
                var comics = await context.QueryAsync<SQLiteComic>(
                    "SELECT * FROM comics WHERE title like ?", "%" + text + "%");

                foreach (var comic in comics)
                {
                    var item = new ComicItem(comic, null)
                    {
                        ComicTitle = comic.Title,
                        Author = comic.Author,
                        ChapterTitle = GetProviderString(comic.Provider),
                    };

                    if (await MethodHelper.FileIsExists("cover\\" + comic.Id))
                    {
                        item.Cover = "ms-appdata:///local/cover/" + comic.Id;
                    }

                    results.Add(item);
                }
            }

            return results;
        }

        public async Task<List<ComicItem>> QueryFavoriteComics()
        {
            List<ComicItem> results = new List<ComicItem>();

            using (DbContext context = new DbContext())
            {
                var comics = await context.QueryAsync<SQLiteComic>(
                    "SELECT comics.* FROM favorites INNER JOIN comics ON favorites.comic_id = comics.id ORDER BY favorites.creation_time DESC");

                foreach (var comic in comics)
                {
                    var item = new ComicItem(comic, null)
                    {
                        ComicTitle = comic.Title,
                        Author = comic.Author,
                    };

                    if (await MethodHelper.FileIsExists("cover\\" + comic.Id))
                    {
                        item.Cover = "ms-appdata:///local/cover/" + comic.Id;
                    }

                    results.Add(item);
                }
            }

            return results;
        }

        public async Task SaveHistoryAsync(int chapterId, int page)
        {
            using (DbContext context = new DbContext())
            {
                var his = await this.GetHistoryAsync(context, chapterId);
                if (his == null)
                {
                    his = new SQLiteHistory()
                    {
                        ChapterId = chapterId,
                        Page = page,
                        LastView = DateTime.Now
                    };

                    await context.InsertAsync(his);
                }
                else
                {
                    his.LastView = DateTime.Now;
                    his.Page = page;

                    await context.UpdateAsync(his);
                }
            }
        }

        public async Task SaveFavoriteAsync(int comicId)
        {
            using (DbContext context = new DbContext())
            {
                var fav = await this.GetFavoriteAsync(context, comicId);
                if (fav == null)
                {
                    fav = new SQLiteFavorite() 
                    {
                        ComicId = comicId,
                        CreationTime = DateTime.Now,
                    };

                    await context.InsertAsync(fav);
                }
            }
        }

        public async Task<SQLiteFavorite> GetFavoriteAsync(int comicId)
        {
            using (DbContext context = new DbContext())
            {
                var fav = await this.GetFavoriteAsync(context, comicId);
                return fav;
            }
        }

        public async Task DelteFavoriteAsync(int comidId)
        {
            using (DbContext context = new DbContext())
            {
                await context.ExecuteAsync(
                    "DELETE FROM favorites WHERE comic_id = ?", comidId);
            }
        }

        #region 辅助方法
        private Task<SQLiteHistory> GetHistoryAsync(DbContext context, int chapterId)
        {
            return context.FirstOrDefault<SQLiteHistory>(
                "SELECT * FROM histories WHERE chapter_id = ? ORDER BY last_view DESC LIMIT 1",
                chapterId);
        }

        private Task<SQLiteComic> GetComicAsync(DbContext context, int id)
        {
            return context.GetAsync<SQLiteComic>(id);
        }

        private Task<SQLiteChapter> GetChapterAsync(DbContext context, int id)
        {
            return context.GetAsync<SQLiteChapter>(id);
        }

        private Task<SQLiteFavorite> GetFavoriteAsync(DbContext context, int comicId)
        {
            return context.FirstOrDefault<SQLiteFavorite>(
                            "SELECT * FROM favorites WHERE comic_id = ? LIMIT 1", comicId);
        }

        private Task<List<SQLitePage>> QueryPagesAsync(DbContext context, int chapterId)
        {
            return context.QueryAsync<SQLitePage>(
                "SELECT * FROM pages WHERE chapter_id = ?", chapterId);
        }

        private static string GetProviderString(string provider)
        {
            try
            {
                return App.Current.Resources[provider].ToString();
            }
            catch
            {
            }

            return string.Empty;
        }
        #endregion
        
        public void Dispose()
        {
        }
    }
}
